%%%-------------------------------------------------------------------
%%% File    : rdf_spalg.erl
%%% Author  :  <vjache>
%%% Description : 
%%%
%%% Created :  2 May 2009 by  <vjache>
%%%-------------------------------------------------------------------
-module(rdf_spalg).

-include("../include/rdf_spalg.hrl").

%% API
-export([visit_patt/2,init_visitor/2,test/0]).

%%====================================================================
%% API
%%====================================================================
init_visitor(VisitModule,Args) ->
	_Visitor={_VisitInnerState=apply(VisitModule,init,Args),VisitModule}.
 
%%--------------------------------------------------------------------
%% Function: 
%% Description:
%%--------------------------------------------------------------------

%%====================================================================
%% Internal functions
%%====================================================================

visit_patt(Patt,{VisitState,VModule}) ->
	visit_patt(Patt,[],{VisitState,VModule}).

visit_patt(Patt,Context,{VisitState,VModule}) ->
	PattContext=[Patt|Context],
	NewVisitState=VModule:begin_visit_patt(PattContext,VisitState),
	{NewVisitState1,VModule}=visit_patt_(Patt,PattContext,{NewVisitState,VModule}),
	{VModule:end_visit_patt(PattContext,NewVisitState1),VModule}.
visit_patt_({?QUAD_TAG_SA,S,P,O,G},Context,{VisitState,VModule}) ->
	lists:foldl(fun({Role,Node},VState) ->
						visit_node(Node,[Role|Context],VState)
				end, {VisitState,VModule}, [{s,S},{p,P},{o,O},{g,G}]);
visit_patt_({?BGP_TAG_SA,QuadPattList},Context,{VisitState,VModule}) ->
	lists:foldl(fun(Quad,VState) ->
						visit_patt(make_tagged_quad(Quad),Context,VState)
				end, {VisitState,VModule}, QuadPattList);
visit_patt_({JoinTag,LeftPatt,RightPattList},Context,{VisitState,VModule}) 
  when JoinTag==?JOIN_TAG_SA orelse JoinTag==?LJOIN_TAG_SA ->
	NewVisitState=visit_patt(LeftPatt,[left|Context],{VisitState,VModule}),
	lists:foldl(fun(RightPatt,VState) ->
						visit_patt(RightPatt,[rigth|Context],VState)
				end, NewVisitState, RightPattList);
visit_patt_({?FILTER_TAG_SA,Patt,BoolExpr},Context,{VisitState,VModule}) ->
	NewVisitState=visit_patt(Patt,Context,{VisitState,VModule}),
	visit_bool(BoolExpr,Context,NewVisitState).

visit_node(Node,Context,{VisitState,VModule}) ->
	NodeContext=[Node|Context],
	NewVisitState=VModule:visit_node(NodeContext,VisitState),
	{NewVisitState,VModule}.
	
visit_bool(BoolExpr,Context,{VisitState,VModule}) ->
	BoolExprContext=[BoolExpr|Context],
	NewVisitState=VModule:begin_visit_bool(BoolExprContext,VisitState),
	{NewVisitState1,VModule}=visit_bool_(BoolExpr,BoolExprContext,{NewVisitState,VModule}),
	{VModule:end_visit_bool(BoolExprContext,NewVisitState1),VModule}.
visit_bool_({BoolTag,ListExpr},Context,{_VisitState,_VModule}=S)
  when 	   BoolTag==?AND_TAG_SA orelse 
		   BoolTag==?OR_TAG_SA->
	lists:foldl(fun(Expr,VState) ->
						visit_bool(Expr,Context,VState)
				end,S,ListExpr);
visit_bool_({?NOT_TAG_SA,Expr},Context,{_VisitState,_VModule}=S) ->
	visit_bool(Expr,Context,S);
visit_bool_({BinPredTag,LeftArg,RightArg},Context,{_VisitState,_VModule}=S)
  when 	   BinPredTag == ?EQUAL_TAG_SA orelse
		   BinPredTag == ?NOTEQUAL_TAG_SA orelse
		   BinPredTag == ?GREATER_TAG_SA orelse
		   BinPredTag == ?LESS_TAG_SA orelse
		   BinPredTag == ?GREATEREQUL_TAG_SA orelse
		   BinPredTag == ?LESSEQUL_TAG_SA orelse
		   BinPredTag == ?REGEX_TAG_SA ->
	NewVisitState=visit_bool_arg(LeftArg,Context,S),
	visit_bool_arg(RightArg,Context,NewVisitState);	
visit_bool_({UnPredTag,Arg},Context,{_VisitState,_VModule}=S) 
  when	   UnPredTag == ?BOUND_TAG_SA orelse
		   UnPredTag == ?ISURI_TAG_SA orelse
		   UnPredTag == ?ISLITERAL_TAG_SA orelse
		   UnPredTag == ?REGEX_TAG_SA ->
	visit_bool_arg(Arg,Context,S).

visit_bool_arg(Arg,Context,{VisitState,VModule}) ->
	NewVisitState=VModule:visit_pred_arg([Arg|Context],VisitState),
	{NewVisitState,VModule}.

make_tagged_quad({?QUAD_TAG_SA,_S,_P,_O,_G}=Q) ->
	Q;
make_tagged_quad({S,P,O,G}) ->
	{?QUAD_TAG_SA,S,P,O,G}.


%%====================================================================
%% Test functions
%%====================================================================
test() ->
	X=x,
	Title=title,
	Price=price,
    Bgp1={'$bgp',
	 [
	  {X,{dc,"title"},Title,'_'}
	 ]
	},
    Bgp2={'$bgp',
	 [
	  {X,{ns,"price"},Price,'_'}
	 ]
	},
	Filter={'$filter',Bgp2,{'$ls',Price,{'$lit',30,number}}},
	Pattern={'$ljoin',Bgp1,[Filter]},
	
	Visitor=init_visitor(rdf_spalg2valg, []),
	visit_patt(Pattern, Visitor).
